# _*_conding:cp-1252-*-
# 教育机构：银杰教育
# 讲师：李伟
# 开发时间：2025/8/30 下午11:45

"""
定义登录夹具
pytest的fixture的定义
1、def 定义一个普通
2、申明夹具： @pytest.fixtrue
3、做登录操作 目的 ： 得到token
  - jsonpath 提取token
4、设置夹具返回值： yield token
"""

"""""""""""

import pytest
from api.login import LoginAPI
from jsonpath import jsonpath
from tools.handle_logs import logger
from api.upload import UploadAPI
from tools.handle_path import photo

# 出现 “空套件（Empty suite）” 的原因是你把夹具命名成了 test_ 开头，导致 pytest 误将其识别为测试用例，
# 但它实际是一个夹具，没有真正的测试逻辑，最终导致 “没有可执行的测试用例”。
@pytest.fixture()  #申明是夹具
def login_fixture():
    logger.info("........前置代码处理.......")
    header = {"Content-Type": "application/json"}
    test = {"principal": "13100009999",
            "credentials": "Admin521314",
            "appType": 3,
            "loginType": 0}
    data = LoginAPI().login(header=header,test_data=test)
    # print(data.text)
    access_token = jsonpath(data.json(),"$..access_token")[0]
    token_type = jsonpath(data.json(),"$..token_type")[0]  # bearer
    token = token_type +  access_token  # 拼接登录之后返回的token 给后面的接口鉴权
    logger.info(f"夹具返回的token:{access_token}")
    yield token  #登录返回的token ，可以设置多个返回值
    print("可以增加后置删除测试数据")

"""""""""""
# 上述：针对小型项目上述可以解决token的 登录问题。
# 但是每次用例调用都会执行一次登录，也会导致频繁的登录。现在
# 一、核心问题：当前 fixture 的作用域是 function（默认）
# pytest 中，fixture 的默认 scope 是 function，即每个测试用例调用 login_fixture 时，
# 都会重新执行 fixture 里的代码（包括登录接口请求）。所以现在的写法会导致 “每个用例都登录一次”，
# 既浪费时间，也可能触发系统 “频繁登录” 的限制。

# 二、改造步骤：控制 fixture 作用域 + 缓存 token
# 要实现 “登录一次，后续复用 token”，需要做两件事：
# 扩大 fixture 的作用域：把 scope 设为 session（整个测试会话只执行一次 fixture）或 module
# （每个模块执行一次 fixture）。存储 token：用 pytest 的 cache 或自定义全局变量，把 token 存起来，后续直接读取，不重复登录。


import pytest
from api.login import LoginAPI
from jsonpath import jsonpath
from tools.handle_logs import logger
import json  # 新增：处理响应为JSON


# 关键：指定scope="session"，整个测试会话只执行一次这个fixture
# 显式声明对request fixture的依赖
@pytest.fixture(scope="session")
def login_fixture(request): # request参数是关键，显式声明依赖
    # 先从pytest的cache中读取已有的token
    cached_token = request.config.cache.get("token", None)
    if cached_token:
        logger.info("从缓存中获取token，跳过登录")
        yield cached_token
        return  # 直接返回缓存的token，不执行后续登录逻辑

    # 缓存中没有token，执行登录
    logger.info("缓存中无token，执行登录...")
    header = {"Content-Type": "application/json"}
    test_data = {
        "principal": "13100009999",
        "credentials": "Admin521314",
        "appType": 3,
        "loginType": 0
    }
    try:
        # 假设LoginAPI().login返回的是response对象，需要转成JSON
        response = LoginAPI().login(header=header, test_data=test_data)
        logger.info(f"登录请求响应状态码：{response.status_code}")
        data_json = response.json()  # 转成JSON字典

        # 安全提取token信息:
        access_token = jsonpath(data_json, "$..access_token")[0]
        token_type = jsonpath(data_json, "$..token_type")[0]
        token = f"{token_type} {access_token}"  # 拼接成Authorization格式
        if not access_token or not token_type:
            raise ValueError("登录响应中未找到acess_token或token_type")
        logger.info(f"登录成功，获取token：{token}")
        # 存入pytest的cache，key为"token"，值为token字符串
        request.config.cache.set("token", token)
        yield token  # 返回token给测试用例
    except Exception as e:
        logger.error(f"登录过程发生错误: {str(e)}", exc_info=True)
        # 抛出异常，让依赖此fixture的测试用例失败
        raise
    finally:
        logger.info("测试会话结束，可执行后置清理操作")
        # fixture的后置逻辑（可选，比如测试结束后清理数据）


# 上文黄色提示不影响使用，属于系统误判。
# 如果多账号登录，会导致token串，所以需要优化缓存不同的账号，登录后分别便签缓存，使用的时候也不会干扰。
# 三、继续优化版
